home *** CD-ROM | disk | FTP | other *** search
/ FM Towns: Free Software Collection 10 / FM Towns Free Software Collection 10.iso / ms_dos / tool / expr / expr.c next >
Text File  |  1995-01-29  |  13KB  |  588 lines

  1. /*
  2.  
  3. VenusScript 式解析ルーチン Version 1.00a
  4. Copyleft 1994 Delmonta
  5.  
  6. このソースプログラムに関する著作権の行使を留保します。
  7.  
  8. コンパイル方法:
  9.     ・コンパイルオプションでマクロ「STANDALONE」を定義してください。
  10.     ・小数対応にするには、コンパイルオプションでマクロ「USE_FLOAT」を
  11.      定義してください。
  12.  
  13. */
  14.  
  15. #include<stdio.h>
  16. #include<stdlib.h>
  17. #include<errno.h>        /* errno */
  18. #include<ctype.h>
  19. #include<string.h>
  20. #include<signal.h>        /* signal() */
  21. #include<float.h>        /* FPE_INTDIV0など */
  22.  
  23. #ifndef    STANDALONE
  24.     #include"venus.h"
  25. #else
  26.     #ifdef    USE_FLOAT
  27.         typedef    double    CONST_T;
  28.     #else
  29.         typedef    long    CONST_T;
  30.     #endif
  31.  
  32.     #define    STRCMP            stricmp    /* これをstrcmpに変えれば   */
  33.                         /* 変数名の大文字・小文字を */
  34.                         /* 厳密に区別する           */
  35.     #define    ISALPHA(c)        (isalpha(c) || (c)=='_')
  36.     #define    ISALNUM(c)        (isalnum(c) || (c)=='_')
  37.     #define    MEMBERSOF(array)    (sizeof(array)/sizeof((array)[0]))
  38.  
  39.     void    errexit(char *,...);
  40. #endif
  41. /*
  42.  
  43. 演算子番号は、次のビット構成を持つ。
  44.  
  45. Bit15   : 1ならば右結合
  46. Bit14   : 1ならば単項演算子
  47. Bit11-4 : 優先順位
  48. Bit3-0  : 演算子個別の識別番号
  49.  
  50. */
  51.  
  52. #define    OP_ENDOFSTACK    0xffff    /* 演算子スタックの終了を示す特別な値 */
  53. #define    OP_LPARE    0xfffe    /* 左括弧      ( */
  54. #define    OP_RPARE    0xfffd    /* 右括弧      ) */
  55.  
  56. #define    OP_LNOT        0xc0f0    /* 論理否定    ! */
  57. #define    OP_NOT        0xc0f1    /* ビット反転  ~ */
  58.  
  59. #define    OP_POW        0x80e0    /* 累乗       ** */
  60.  
  61. #define    OP_SMINUS    0xc0d0    /* 負の符号    - */
  62. #define    OP_SPLUS    0xc0d1    /* 正の符号    + */
  63.  
  64. #define    OP_MULT        0x00c0    /* 乗算        * */
  65. #define    OP_DIV        0x00c1    /* 除算        / */
  66. #define    OP_MOD        0x00c2    /* 剰余        % */
  67.  
  68. #define    OP_LSHIFT    0x00b0    /* 左シフト   << */
  69. #define    OP_RSHIFT    0x00b1    /* 右シフト   >> */
  70.  
  71. #define    OP_PLUS        0x00a0    /* 加算        + */
  72. #define    OP_MINUS    0x00a1    /* 減算        - */
  73.  
  74. #define    OP_AND        0x0090    /* ビットAND   & */
  75. #define    OP_XOR        0x0091    /* ビットXOR   ^ */
  76. #define    OP_OR        0x0092    /* ビットOR    | */
  77.  
  78. #define    OP_LESS        0x0080    /* 比較       <  */
  79. #define    OP_ELESS    0x0081    /*            <= */
  80. #define    OP_GREAT    0x0082    /*            >  */
  81. #define    OP_EGREAT    0x0083    /*            >= */
  82. #define    OP_EQUAL    0x0084    /*            == */
  83. #define    OP_NEQUAL    0x0085    /*            != */
  84.  
  85. #define    OP_LET        0x8070    /* 代入        = */
  86.  
  87. #define    OP_LAND        0x0060    /* 論理AND    && */
  88. #define    OP_LOR        0x0061    /* 論理OR     || */
  89.  
  90. #define    OPLEVEL(op)    ((op) & 0x0ff0)
  91. #define    ISRIGHT(op)    ((op) & 0x8000)
  92. #define    ISSINGLE(op)    ((op) & 0x4000)
  93. /*-----------------------------------型--------------------------------------*/
  94. typedef    int    OPERATOR_T;    /* 演算子   */
  95. typedef    int    VARNO_T;    /* 変数番号 */
  96. typedef    struct
  97. {
  98.     enum {CONSTANT,VARIABLE,OPERATOR,ENDOFSTRING} type;
  99.     union
  100.     {    CONST_T        constant;    /* 定数   */
  101.         int        varno;        /* 変数   */
  102.         OPERATOR_T    op;        /* 演算子 */
  103.     } data;
  104. } TOKEN_T;
  105.  
  106. static    TOKEN_T    Token;
  107.  
  108. static    struct    VAR_T
  109. {
  110.     CONST_T    value;
  111.     char    *name;
  112. } Variable[256];
  113.  
  114. static    struct    VSTACK
  115. {
  116.     union    {CONST_T constant; VARNO_T varno;}    value;
  117.     enum    {VSTK_VAR,VSTK_CONST}            type;
  118. } Vstack[256];
  119.  
  120. static    OPERATOR_T    Ostack[256];
  121.  
  122. static    int    Vstackp;
  123. static    int    Ostackp;
  124.  
  125. static    char    *Expr;
  126. /*-----------------------------初期化とエラー処理----------------------------*/
  127. static    void    initexpr(char *s)
  128. {
  129.     Token.type = ENDOFSTRING;
  130.     Vstackp = Ostackp = 0;
  131.  
  132.     Expr = s;
  133. }
  134.  
  135. void    fperr(int a,int b)
  136. {
  137.     switch    (b)
  138.     {
  139.     case FPE_INTDIV0:
  140.     case FPE_ZERODIVIDE:
  141.         errexit("0で割りました");
  142.     case FPE_OVERFLOW:
  143.         errexit("オーバーフローしました");
  144.     case FPE_UNDERFLOW:
  145.         errexit("アンダーフローしました");
  146.     case FPE_INVALID:
  147.         errexit("不正な演算を実行しました");
  148.     }
  149.     signal(SIGFPE,fperr);        /* デノーマル数などは問題にしない */
  150. }
  151. /*---------------------------スタックフレームの管理--------------------------*/
  152. static    OPERATOR_T    popop(void)
  153. {
  154.     if    (Ostackp==0)
  155.         return OP_ENDOFSTACK;
  156.     else
  157.         return Ostack[--Ostackp];
  158. }
  159.  
  160. static    void    pushop(OPERATOR_T op)
  161. {
  162.     if    (op==OP_ENDOFSTACK)
  163.         return;
  164.     else if    (Ostackp==MEMBERSOF(Ostack))
  165.         errexit("演算子スタックオーバーフロー.");
  166.     else
  167.         Ostack[Ostackp++] = op;
  168. }
  169.  
  170. static    char    Vstack_overflow[] = "オペランドスタックオーバーフロー.";
  171.  
  172. static    void    pushconst(CONST_T val)
  173. {
  174.     if    (Vstackp==MEMBERSOF(Vstack))
  175.         errexit(Vstack_overflow);
  176.     else
  177.     {
  178.         Vstack[Vstackp].type = VSTK_CONST;
  179.         Vstack[Vstackp++].value.constant = val;
  180.     }
  181. }
  182.  
  183. static    void    pushvar(VARNO_T varno)
  184. {
  185.     if    (Vstackp==MEMBERSOF(Vstack))
  186.         errexit(Vstack_overflow);
  187.     else
  188.     {
  189.         Vstack[Vstackp].type = VSTK_VAR;
  190.         Vstack[Vstackp++].value.varno = varno;
  191.     }
  192. }
  193.  
  194. static    char    Vstack_underflow[] = "オペランドが足りません.";
  195.  
  196. static    CONST_T    popconst(void)
  197. {
  198.     if    (Vstackp==0)
  199.         errexit(Vstack_underflow);
  200.     else if    (Vstack[--Vstackp].type==VSTK_CONST)
  201.         return Vstack[Vstackp].value.constant;
  202.     else
  203.         return Variable[Vstack[Vstackp].value.varno].value;
  204. }
  205.  
  206. static    VARNO_T    popvar(void)
  207. {
  208.     if    (Vstackp==0)
  209.         errexit(Vstack_underflow);
  210.     else if    (Vstack[--Vstackp].type==VSTK_CONST)
  211.         errexit("変数が要求されるところに右辺式があります.");
  212.     else
  213.         return Vstack[Vstackp].value.varno;
  214. }
  215. /*-----------------------------------計算------------------------------------*/
  216. #ifdef    USE_FLOAT
  217.     #include<math.h>
  218.     static    CONST_T    POW(CONST_T x,CONST_T y)
  219.     {
  220.         if    (x==0)        /* y<=0でも0**y==1 */
  221.             return 1;
  222.         else if    (x<0 && y!=ceil(y))
  223.             errexit("負の数に対する指数が整数になっていません");
  224.         else
  225.             return pow(x,y);
  226.     }
  227. #else
  228.     static    CONST_T    POW(CONST_T x,CONST_T y)
  229.     {
  230.         if    (y==0)        /* y<=0でも0**y==1 */
  231.             return 1;
  232.         else if    (y<0)
  233.             return 0;    /* 切り捨てられて結果は0 */
  234.         else
  235.         {
  236.             CONST_T    z = x;
  237.  
  238.             while    (--y)
  239.                 z *= x;
  240.  
  241.             return z;
  242.         }
  243.     }
  244. #endif
  245. /*-------------------------------演算子の処理--------------------------------*/
  246. static    void    getoperator(void)
  247. {
  248.     int    flag = Token.type==ENDOFSTRING ||
  249.             (Token.type==OPERATOR && Token.data.op!=OP_RPARE);
  250.             /* 直前のトークンは2項演算子の前に来ないものか */
  251.  
  252.     switch    (*Expr)
  253.     {
  254.     case '(':    Token.data.op = OP_LPARE;    break;
  255.     case ')':    Token.data.op = OP_RPARE;    break;
  256.     case '!':
  257.         if    (*(Expr+1)=='=')
  258.             Expr++,Token.data.op = OP_NEQUAL;
  259.         else
  260.             Token.data.op = OP_LNOT;
  261.         break;
  262.     case '~':    Token.data.op = OP_NOT;    break;
  263.     case '*':
  264.         if    (*(Expr+1)=='*')
  265.             Expr++,Token.data.op = OP_POW;
  266.         else
  267.             Token.data.op = OP_MULT;
  268.         break;
  269.     case '+':
  270.         if    (flag)
  271.             Token.data.op = OP_SPLUS;
  272.         else
  273.             Token.data.op = OP_PLUS;
  274.         break;
  275.     case '-':
  276.         if    (flag)
  277.             Token.data.op = OP_SMINUS;
  278.         else
  279.             Token.data.op = OP_MINUS;
  280.         break;
  281.     case '/':    Token.data.op = OP_DIV;    break;
  282.     case '%':    Token.data.op = OP_MOD;    break;
  283.     case '<':
  284.         if    (*(Expr+1)=='<')
  285.             Expr++,Token.data.op = OP_LSHIFT;
  286.         else if    (*(Expr+1)=='=')
  287.             Expr++,Token.data.op = OP_ELESS;
  288.         else
  289.             Token.data.op = OP_LESS;
  290.         break;
  291.     case '>':
  292.         if    (*(Expr+1)=='>')
  293.             Expr++,Token.data.op = OP_RSHIFT;
  294.         else if    (*(Expr+1)=='=')
  295.             Expr++,Token.data.op = OP_EGREAT;
  296.         else
  297.             Token.data.op = OP_GREAT;
  298.         break;
  299.     case '&':
  300.         if    (*(Expr+1)=='&')
  301.             Expr++,Token.data.op = OP_LAND;
  302.         else
  303.             Token.data.op = OP_AND;
  304.         break;
  305.     case '|':
  306.         if    (*(Expr+1)=='|')
  307.             Expr++,Token.data.op = OP_LOR;
  308.         else
  309.             Token.data.op = OP_OR;
  310.         break;
  311.     case '^':    Token.data.op = OP_XOR;
  312.     case '=':
  313.         if    (*(Expr+1)=='=')
  314.             Expr++,Token.data.op = OP_EQUAL;
  315.         else
  316.             Token.data.op = OP_LET;
  317.         break;
  318.     default:
  319.         errexit("不正な演算子です:%c",*Expr);
  320.     };
  321.  
  322.     if    (flag && !ISSINGLE(Token.data.op))
  323.         errexit("2つの演算子が連続しています");
  324.  
  325.     Expr++;
  326.     Token.type = OPERATOR;
  327. }
  328.  
  329. static    void    evalop(OPERATOR_T op)
  330. {
  331.     CONST_T    a;
  332.  
  333.     switch    (op)
  334.     {
  335.     case OP_LPARE:
  336.         errexit("'('に対応する')'がありません");
  337.  
  338.     case OP_LNOT:    a = !popconst();            break;
  339.     case OP_NOT:    a = ~(long)popconst();            break;
  340.     case OP_POW:    a = popconst();    a = POW(popconst(),a);    break;
  341.     case OP_SPLUS:    a = popconst();                break;
  342.     case OP_SMINUS:    a = -popconst();            break;
  343.     case OP_MULT:    a = popconst() * popconst();        break;
  344.     case OP_DIV:    a = popconst();    a = popconst()/a;    break;
  345.     case OP_MOD:
  346.         a = popconst();
  347.         #ifndef    USE_FLOAT
  348.             a = popconst() % a;
  349.         #else
  350.             a = fmod(popconst(),a);
  351.         #endif
  352.         break;
  353.     case OP_PLUS:    a = popconst() + popconst();        break;
  354.     case OP_MINUS:    a = popconst();    a = popconst() - a;    break;
  355.     case OP_LSHIFT:
  356.         a = popconst();
  357.         #ifndef    USE_FLOAT
  358.             a = popconst() << a;
  359.         #else
  360.             a = ldexp(popconst(),a);
  361.         #endif
  362.         break;
  363.     case OP_RSHIFT:
  364.         a = popconst();
  365.         #ifndef    USE_FLOAT
  366.             a = popconst() >> a;
  367.         #else
  368.             a = ldexp(popconst(),-a);
  369.         #endif
  370.         break;
  371.             /* OP_LANDとOP_LORで一度aに値を設定しているのは */
  372.             /* Cの&&あるいは||では第1項だけで値が確定すれば */
  373.             /* 第2項は評価しないため                        */
  374.     case OP_AND:    a =(long)popconst() & (long)popconst();    break;
  375.     case OP_XOR:    a =(long)popconst() ^ (long)popconst();    break;
  376.     case OP_OR:    a =(long)popconst() | (long)popconst();    break;
  377.     case OP_LAND:    a = popconst(); a = popconst() && a;    break;
  378.     case OP_LOR:    a = popconst(); a = popconst() || a;    break;
  379.     case OP_LESS:    a = popconst();    a = popconst() <  a;    break;
  380.     case OP_ELESS:    a = popconst();    a = popconst() <= a;    break;
  381.     case OP_GREAT:    a = popconst();    a = popconst() >  a;    break;
  382.     case OP_EGREAT:    a = popconst();    a = popconst() >= a;    break;
  383.     case OP_EQUAL:    a = popconst() == popconst();        break;
  384.     case OP_NEQUAL:    a = popconst() != popconst();        break;
  385.     case OP_LET:
  386.         {
  387.             VARNO_T    b;
  388.  
  389.             a = popconst();
  390.             b = popvar();
  391.             Variable[b].value = a;
  392.         }
  393.         break;
  394.     default:
  395.         errexit("不正な演算子です:演算子ID 0x%04X",op);
  396.     }
  397.     pushconst(a);
  398. }
  399. /*----------------------------トークンの切り出し-----------------------------*/
  400. static    char    Couple_values[] = "2つの定数/変数が連続して表記されています";
  401.  
  402. static    void    getvariable(void)
  403. {
  404. static    VARNO_T    varnum = 0;    /* 変数の総数 */
  405.     char    *p = Expr;
  406.     char    c;
  407.     VARNO_T    i;
  408.  
  409.     if    (Token.type==CONSTANT || Token.type==VARIABLE)
  410.         errexit(Couple_values);
  411.  
  412.     while    (ISALNUM(*p))
  413.         p++;
  414.  
  415.     c  = *p;
  416.     *p = '\0';
  417.  
  418.     for    (i=0 ; i<varnum ; i++)
  419.     {
  420.         if    (STRCMP(Expr,Variable[i].name)==0)
  421.             goto end;
  422.     }
  423.  
  424.     varnum++;
  425.  
  426.     if    (i==MEMBERSOF(Variable))
  427.         errexit("変数は最大で%d個までです",i);
  428.  
  429.     if    ((Variable[i].name=strdup(Expr))==NULL)
  430.         errexit("メモリ不足です");
  431.  
  432.     Variable[i].value = 0;
  433. end:
  434.     Token.type = VARIABLE;
  435.     Token.data.varno = i;
  436.  
  437.     Expr = p;
  438.     *p = c;
  439. }
  440.  
  441. static    int    expr_gettoken(void)
  442. {
  443.     while    (isspace(*Expr))
  444.         Expr++;
  445.  
  446.     if    (*Expr=='\0')    /* 文字列の終わり */
  447.         return 0;
  448.                 /* 定数か? */
  449.     if    (isdigit(*Expr) || *Expr=='.')
  450.     {        /* ピリオドとの比較は整数に限定する場合は意味がない */
  451.         CONST_T    val;
  452.  
  453.         if    (Token.type==CONSTANT || Token.type==VARIABLE)
  454.             errexit(Couple_values);
  455.  
  456.         errno = 0;
  457.         if    (*Expr=='0' && (Expr[1]=='x' || Expr[1]=='X'))
  458.             val = (long)strtoul(Expr+2,&Expr,16);
  459.         else
  460.         {
  461.             #ifdef    USE_FLOAT
  462.                 val = strtod(Expr,&Expr);
  463.             #else
  464.                 val = strtoul(Expr,&Expr,10);
  465.             #endif
  466.         }
  467.  
  468.         if    (errno==ERANGE && val!=0)
  469.             errexit("定数の値が大きすぎます.");
  470.  
  471.         Token.data.constant = val;
  472.         Token.type = CONSTANT;
  473.     }
  474.     else if    (ISALPHA(*Expr))
  475.         getvariable();
  476.     else
  477.         getoperator();
  478.  
  479.     return 1;
  480. }
  481. /*------------------------------メインルーチン-------------------------------*/
  482. extern    CONST_T    evalexpr(char *s)
  483. {
  484.     OPERATOR_T    op;
  485.     int        lev1,lev2;
  486.  
  487.     initexpr(s);
  488.     while    (expr_gettoken())
  489.     {
  490.         switch    (Token.type)
  491.         {
  492.         case CONSTANT:
  493.             pushconst(Token.data.constant);
  494.             break;
  495.         case VARIABLE:
  496.             pushvar(Token.data.varno);
  497.             break;
  498.         case OPERATOR:
  499.             if    (Token.data.op==OP_LPARE)
  500.             {
  501.                 pushop(OP_LPARE);
  502.                 break;
  503.             }
  504.             if    (Token.data.op==OP_RPARE)
  505.             {
  506.                 while    ((op=popop())!=OP_LPARE)
  507.                 {
  508.                     if    (op==OP_ENDOFSTACK)
  509.                         errexit("')'に対応する'('がありません.");
  510.                     evalop(op);
  511.                 }
  512.                 break;
  513.             }
  514.  
  515.             op = popop();
  516.             lev1 = OPLEVEL(op);
  517.             lev2 = OPLEVEL(Token.data.op);
  518.             if    (op==OP_LPARE || op==OP_ENDOFSTACK ||
  519.                  ISSINGLE(Token.data.op) ||
  520.                  lev1<lev2 || (lev1==lev2 && ISRIGHT(op)) )
  521.                 pushop(op);
  522.             else
  523.                 evalop(op);
  524.  
  525.             pushop(Token.data.op);
  526.             break;
  527.         }
  528.     }
  529.     while    ((op=popop())!=OP_ENDOFSTACK)
  530.         evalop(op);
  531.  
  532.     if    (Vstackp!=1)
  533.         printf("Vstackp==%d\n",Vstackp);
  534.  
  535.     return popconst();
  536. }
  537.  
  538. /*---------------スタンドアローンの計算ツールとして使用する場合--------------*/
  539. #ifdef    STANDALONE
  540.     #include<setjmp.h>
  541.     #include<stdarg.h>
  542.  
  543.     jmp_buf    Jmp_buf;
  544.  
  545.     void    errexit(char *s,...)
  546.     {
  547.         va_list    ap;
  548.  
  549.         va_start(ap,s);
  550.         vprintf(s,ap);
  551.         va_end(ap);
  552.  
  553.         putchar('\a');
  554.         putchar('\n');
  555.         longjmp(Jmp_buf,1);
  556.     }
  557.  
  558.     int    main(int argc,char **argv)
  559.     {
  560.         char    buf[256];
  561.  
  562.         #ifdef    USE_FLOAT
  563.             #define    VER    "(小数対応バージョン)"
  564.         #else
  565.             #define    VER    "(整数限定バージョン)"
  566.         #endif
  567.  
  568.         printf(    "式計算ユーティリティ" VER " Version 1.00a\n"
  569.             "Copyleft 1994 Delmonta\n");
  570.  
  571.         #undef    VER
  572.  
  573.         setjmp(Jmp_buf);
  574.         signal(SIGFPE,fperr);
  575.  
  576.         while    (printf(">"),fgets(buf,sizeof(buf),stdin)&&*buf!='\n')
  577.         {
  578.             #ifdef    USE_FLOAT
  579.                 printf("%.*g\n",DBL_DIG+1,evalexpr(buf));
  580.                     /* i80x87のdoubleの精度は10進で15.95 */
  581.                     /* 桁だがDBL_DIG=15と定義されている */
  582.             #else
  583.                 printf("%ld\n",evalexpr(buf));
  584.             #endif
  585.         }
  586.     }
  587. #endif
  588.